using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using WarningForeverClone.Input;
using WarningForeverClone.src.ships;
using WarningForeverClone.src.weapons;
using WarningForeverClone.src.ui;
using WarningForeverClone.src.particles;

namespace WarningForeverClone
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class MainGame : Microsoft.Xna.Framework.Game
    {
        static Point screenSize = new Point(1280, 768);
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Ship ship;
        InputHandler input;
        Boss boss;

        PlayerModel playerModel;

        UI ui;
        GameState state;

        int level = 0;
        Random rand;

        public static ParticleManager particleManager;

        static int maxParticleCount = 20;
        int particleCount = 0;


        public MainGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.PreferredBackBufferWidth = screenSize.X;
            graphics.PreferredBackBufferHeight = screenSize.Y;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();

            input = new InputHandler();
            rand = new Random();
            playerModel = new PlayerModel();
            StartLevel();
        }
        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            contentManager = Content;

            spriteBatch = new SpriteBatch(GraphicsDevice);

            ui = new UI(0, 0, screenSize.X, screenSize.Y);
            ui.LoadContent(Content);

            particleManager = new ParticleManager();
        }
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            CheckInput();

            switch (state)
            {
                case GameState.Playing:
                    ship.KeepOnScreen(0, 0, screenSize.X, screenSize.Y);
                    ship.UpdateShots(boss);
                    boss.Update(ship, playerModel);
                    playerModel.Update(ship);

                    if (!boss.Alive)
                    {
                        EndLevel();
                    }
                    else
                    {
                        boss.Move();
                        boss.KeepOnScreen(0, 0, screenSize.X, screenSize.Y);
                    }

                    maxParticleCount = 5+(int)(ship.health / 100 * 40);
                    if (particleCount > maxParticleCount && ship.health < 80)
                    {
                        particleManager.CreateMiss(ship.Position + 
                            new Vector2(ship.Width / 2, ship.Height / 2) + 
                            new Vector2(rand.Next(60)-30,rand.Next(60)-30));
                        particleCount = 0;
                    }
                    particleCount++;

                    if (ship.health <= 0)
                    {
                        state = GameState.Died;
                    }

                    particleManager.Update();
                    break;
                case GameState.Evolving:
                    break;
            }

            base.Update(gameTime);
        }
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();

            //draw stuff here
            switch (state)
            {
                case GameState.Playing:
                    ship.Draw(spriteBatch);
                    foreach (Weapon w in ship.ShotsFired)
                    {
                        w.Draw(spriteBatch);
                    }

                    boss.Draw(spriteBatch);
                    foreach (Weapon w in boss.ShotsFired)
                    {
                        w.Draw(spriteBatch);
                    }

                    //particles
                    spriteBatch.End();
                    spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.Additive);
                    particleManager.Draw(spriteBatch);
                    spriteBatch.End();
                    spriteBatch.Begin();

                    ui.DrawAvailableWeapons(spriteBatch, ship);

                    spriteBatch.DrawString(ui.Fonts["Calibri14"], "Level: " + level, new Vector2(5,5), Color.White);

                    spriteBatch.DrawString(ui.Fonts["Calibri14"], "Health: " + ship.health,
                        new Vector2(ScreenSize.X, 0) + new Vector2(-300 + 5, 5),
                        Color.White);
                    spriteBatch.DrawString(ui.Fonts["Calibri14"], "Boss Health: " + boss.Health,
                        new Vector2(ScreenSize.X, 20) + new Vector2(-300 + 5, 5),
                        Color.White);
                    break;
                case GameState.Evolving:
                    spriteBatch.DrawString(ui.Fonts["Calibri14"], "Press Enter to start the next level.", new Vector2(20, 20), Color.White);
                    break;
                case GameState.Died:
                    spriteBatch.DrawString(ui.Fonts["Calibri14"], "You died! Press escape to exit.", new Vector2(20, 20), Color.White);
                    break;
            }


            spriteBatch.End();
            base.Draw(gameTime);
        }

        private void CheckInput()
        {
            input.UpdateInput(false, 0);

            switch (state)
            {
                case GameState.Evolving:

                    if (input.IsKeyDown(Keys.Escape))
                        this.Exit();
                    if (input.KeyPressed(Keys.Enter))
                    {
                        StartLevel(true);
                    }
                    break;
                case GameState.Playing:
                    if (input.IsKeyDown(Keys.Escape))
                        this.Exit();

                    bool moving = false;

                    if (input.IsKeyDown(Keys.Left) || input.IsKeyDown(Keys.A))
                    {
                        ship.MoveLeft();
                        moving = true;
                    }
                    else if (input.IsKeyDown(Keys.Right) || input.IsKeyDown(Keys.D))
                    {
                        ship.MoveRight();
                        moving = true;
                    }

                    if (input.IsKeyDown(Keys.Up) || input.IsKeyDown(Keys.W))
                    {
                        ship.MoveForward();
                        moving = true;
                    }
                    else if (input.IsKeyDown(Keys.Down) || input.IsKeyDown(Keys.S))
                    {
                        ship.MoveBackward();
                        moving = true;
                    }

                    if (moving)
                        playerModel.moveTick();

                    if (input.IsKeyDown(Keys.Space))
                    {
                        ship.FireSelectedWeapon();
                    }

                    if (input.IsKeyDown(Keys.D1))
                    {
                        ship.ChangeWeapon("greenLaser");
                    }
                    else if (input.IsKeyDown(Keys.D2))
                    {
                        ship.ChangeWeapon("blueLaser");
                    }
                    else if (input.IsKeyDown(Keys.D3))
                    {
                        ship.ChangeWeapon("redLaser");
                    }
                    break;
                case GameState.Died:

                    if (input.IsKeyDown(Keys.Escape))
                        this.Exit();

                    break;
            }
        }
        private void StartLevel(bool evolving = false)
        {
            string lastWeapon = String.Empty;
            if (evolving)
            {
                lastWeapon = ship.SelectedWeapon;
            }


            ship = new Ship(new Vector2(500, 600));
            ship.LoadContent(Content);

            if (evolving)
            {
                ship.ChangeWeapon(lastWeapon);
            }

            level++;
            if (!evolving)
                boss = Boss.CreateBoss(level, ship, 2);
            else
            {
                if (playerModel.LevelTime < 550) // Finished level quickly, increase difficulty more
                    level++;
                playerModel.calculateModel(ship, boss, level);
                playerModel.LevelTime = 0;

                float newSpeed = boss.Speed + Math.Max((1.0f - playerModel.ShipMovePercentTime) * 0.8f, 0.5f);

                float highestWeaponPercent = Math.Max(Math.Max(playerModel.GreenLaserPercentTime, playerModel.BlueLaserPercentTime), playerModel.RedLaserPercentTime);
                int newHullShield;
                if (highestWeaponPercent == playerModel.GreenLaserPercentTime)
                    newHullShield = 0;
                else if (highestWeaponPercent == playerModel.BlueLaserPercentTime)
                    newHullShield = 1;
                else
                    newHullShield = 2;

                String newWC = playerModel.GetNewWeaponConfig();

                boss = Boss.CreateBoss(level, ship, newHullShield, newSpeed, newWC);
            }
            boss.LoadContent(Content);

            particleManager.Clear();
            particleCount = 0; 

            state = GameState.Playing;
        }
        private void EndLevel()
        {
            state = GameState.Evolving;
        }



        private static ContentManager contentManager;
        public static ContentManager ContentManager
        {
            get { return contentManager; }
        }

        public static Point ScreenSize
        {
            get { return MainGame.screenSize; }
        }
    }

    enum GameState
    {
        Playing, Evolving, Died
    }
}
